package cn.hpclub.server.controller.admin;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.aop.Before;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;

import cn.hpclub.server.constant.Constant;
import cn.hpclub.server.model.Permission;
import cn.hpclub.server.model.SysRole;
import cn.hpclub.server.model.SysRolePermission;
import cn.hpclub.server.model.SysUserRole;
import cn.hpclub.server.role.PermissionNode;
import cn.hpclub.server.role.PermissionTree;
import cn.hpclub.server.role.RoleBean;
import cn.hpclub.server.util.InterfaceUtil;

/**
 * 后台类 - 角色
 * 
 */
public class RoleController extends BaseAdminController<SysRole>{
    private static Logger       log                        = LoggerFactory.getLogger(RoleController.class);
    private static final String SELECTED_PERMISSION_PREFIX = "rptList$ctl$cblActionType$";
    private static final int[]  ROLE_TYPE_ARRAY            = new int[] { Constant.ROLE_TYPE_ADMIN,
            Constant.ROLE_TYPE_SUPPLIER_ADMIN, Constant.ROLE_TYPE_GOV_ENTERPRISE };

    /**
     * @Title: 创建角色
     */
    public void create(){
        int adminRoleId = getAdminRoleId();
        List<RoleBean> roleLevels = getRoleLevels(adminRoleId, 0);
        roleLevels.get(0).setSelected(true);
        PermissionNode root = PermissionTree.getPermissionNodeTree(adminRoleId);
        root.printNodes("");
        setAttr("permnode", root);
        setAttr("roleID", -1);
        setAttr("isActive", true);
        setAttr("level", roleLevels);
        List<RoleBean> roleTypes = getRoleTypes(adminRoleId, 0);
        setAttr("type", roleTypes);
        setAttr("selectedType", roleLevels.get(0).getValue());
        render("/admin/role_input.tpl");
    }

    /**
     * @Title: 获取角色列表
     */
    public void list(){
        log.debug("RoleController.list");
        ConcurrentHashMap<String, String> searchInfo = getSearchInfo();;
        findByPageByRoleLevel(searchInfo);
        setAttrs(searchInfo);
        render("/admin/role_list.tpl");
    }

    /*
     * 角色dialog
     */
    public void dialog(){
        findActiveRoleByPageByRoleLevel(this.getKeyword());
        setAttr("keyword", this.getKeyword());
        render("/admin/role_dialog.tpl");
    }

    /**
     * @Title: 保存角色数据(For Add & Edit)
     */
    @Before({ Tx.class })
    public void save(){
        int adminId = getAdminId();
        int roleId = getParaToInt("roleID");
        if(-1 == roleId){
            // 新增角色
            roleId = addToRoleTable(adminId);
        } else{
            // 修改角色
            updateToRoleTable(adminId, roleId);
            // 删除原"角色-权限"映射关系
            SysRolePermission.dao.deleteRolePermission(roleId);
        }
        // 获取权限选中PermissionID，写入sys_role_permission
        saveRolePermission(roleId);
        redirect("/role/list");
    }

    /**
     * @Title: 保存角色权限到sys_role_permission
     * @param roleId
     *            角色ID
     */
    private void saveRolePermission(int roleId){
        /* 从数据库获取所有权限ID-ParentID映射集合 */
        Map<String, String> allPermissionMap = getAllPermissionMap();
        /* 从参数中获取选中权限ID列表 */
        List<String> selectPermissinoIdList = getSelectPermissionIdFromParams(getParaMap(), allPermissionMap);
        /* 保存选中权限ID---->sys_role_permission表 */
        saveSelectedPermissionIdList(roleId, selectPermissinoIdList);
    }

    /**
     * @Title: 保存选中权限ID---->sys_role_permission表
     * @param roleId
     *            角色ID
     * @param selectPermissinoIdList
     *            选中权限ID列表 void
     */
    private void saveSelectedPermissionIdList(int roleId, List<String> selectPermissinoIdList){
        for(String pId : selectPermissinoIdList){
            save2RolePermission(roleId, pId);
        }
    }

    /**
     * @Title: 从http参数中获取选中permission
     * @param paraMap
     *            http参数
     * @param allPermissionIDMap
     *            DB中所有权限ID集合
     * @return Map<String,String> 选中PermissionID以及其父节点集合
     */
    private List<String> getSelectPermissionIdFromParams(Map<String, String[]> paraMap,
            Map<String, String> allPermissionIDMap){
        List<String> selectPermissinoIDList = new ArrayList<String>();
        for(Map.Entry<String, String[]> entry : paraMap.entrySet()){
            if(entry.getKey().startsWith(SELECTED_PERMISSION_PREFIX)){
                String[] value = entry.getValue();
                for(int i = 0; i < value.length; i++){
                    log.debug("value=" + value[i]);
                    String perId = value[0];
                    putParentPermissionIntoMap(allPermissionIDMap, selectPermissinoIDList, perId);
                }
            }
        }
        return selectPermissinoIDList;
    }

    /**
     * @Title: 找出当前节点的父节点，并放入Map中
     * @param allPermissionMap
     *            所有权限节点Map
     * @param addPermissionMap
     *            新增角色权限Map
     * @param permID
     *            权限节点ID void
     */
    private void putParentPermissionIntoMap(Map<String, String> allPermissionMap, List<String> selectPermissinoIDList,
            String permID){
        /* 找出父节点，添加到待插入PermissionMaps中 */
        String pid = permID;
        while(true){
            String parentID = allPermissionMap.get(pid);
            if(pid.equals("0")){
                break;
            } else{
                log.debug("pid=" + pid + ",parentID=" + parentID);
                if(!selectPermissinoIDList.contains(pid)){
                    selectPermissinoIDList.add(pid);
                }
                pid = parentID;
            }
        }
    }

    private void save2RolePermission(int roleId, String permissionId){
        SysRolePermission rolePerm = new SysRolePermission();
        rolePerm.set("role_id", roleId);
        rolePerm.set("permission_id", permissionId);
        rolePerm.set("created_by", getAdminId());
        rolePerm.set("created_time", new Date());
        rolePerm.save();
    }

    /**
     * @Title: 从数据库获取所有权限ID-ParentID映射集合
     * @return Map<String,String>
     */
    private Map<String, String> getAllPermissionMap(){
        List<Permission> allPermission = Permission.dao.getAllPermission();
        Map<String, String> permIdMaps = new HashMap<String, String>();
        for(Permission perm : allPermission){
            permIdMaps.put(String.valueOf(perm.getInt("id")), String.valueOf(perm.getInt("parent_id")));
        }
        return permIdMaps;
    }

    /**
     * @Title: 新增角色
     * @param adminId
     *            当前操作的管理员ID
     * @return int 新增角色ID
     */
    private int addToRoleTable(int adminId){
        SysRole role = getModel(SysRole.class);
        role.set("name", getPara("roleName"));
        role.set("description", getPara("roleName"));
        role.set("level", getPara("roleLevel"));
        role.set("is_active", ("true".equals(getPara("radioActive")) ? 1 : 0));
        role.set("created_by", adminId);
        role.set("created_time", new Date());
        role.set("last_updated_by", adminId);
        role.set("last_updated_time", new Date());
        role.set("type", getPara("roleType"));
        role.save();
        return role.get("id");
    }

    /**
     * @Title: 更新角色数据--->sys_role
     * @param adminId
     *            当前操作的管理ID
     * @param roleId
     *            角色ID void
     */
    private void updateToRoleTable(int adminId, int roleId){
        SysRole role = getModel(SysRole.class);
        role.set("id", roleId);
        role.set("name", getPara("roleName"));
        role.set("description", getPara("roleName"));
        role.set("level", getPara("roleLevel"));
        role.set("type", getPara("roleType"));
        role.set("is_active", ("true".equals(getPara("radioActive")) ? 1 : 0));
        role.set("last_updated_time", new Date());
        role.set("last_updated_by", adminId);
        role.update();
    }

    /**
     * @Title:编辑角色
     */
    public void edit(){
        int id = getParaToInt("id", -1);
        int adminRoleId = getAdminRoleId();
        SysRole role = SysRole.dao.findById(id);
        PermissionNode root = PermissionTree.getPermissionNodeTreeForEdit(adminRoleId, id);
        List<RoleBean> roleLevels = getRoleLevels(adminRoleId, role.getInt("level"));
        List<RoleBean> roleTypes = getRoleTypes(adminRoleId, role.getInt("type"));

        setAttr("permnode", root);
        setAttr("roleID", id);
        setAttr("type", role.getInt("type"));
        setAttr("roleName", role.getStr("name"));
        setAttr("level", roleLevels);
        setAttr("type", roleTypes);
        setAttr("selectedType", role.getInt("type"));
        setAttr("isActive", role.getBoolean("is_active"));
        render("/admin/role_input.tpl");
    }

    /**
     * @Title: 获取当前登录后台系统帐号的角色ID
     * @return int 角色ID
     */
    private int getAdminRoleId(){
        int adminId = getAdminId();
        SysUserRole userRole = SysUserRole.dao.findFirst("select role_id from sys_user_role where user_id=? ", adminId);
        int adminRoleId = userRole.getInt("role_id");
        return adminRoleId;
    }

    // 删除
    @Before(Tx.class)
    public void delete() throws SQLException{
        String[] ids = getParaValues("ids");
        if(ids == null || ids.length == 0){
            ajaxJsonErrorMessage("删除失败，无选中项！");
            return;
        }
        deleteSelectedPermission(ids);
    }

    /**
     * @Title: 根据编辑页面的RoleID和RoleName，检查DB中是否存在与RoleName相同角色名
     * @Description: void
     */
    public void check(){
        int roleID = getParaToInt("role_id");
        String roleName = getPara("role_name");
        Record record = Db.findFirst("select COUNT(1) cnt from sys_role where id <>? and name=? and is_deleted=0",
                                     roleID, roleName);
        long count = record.getLong("cnt");
        log.info("check.count=" + count);
        renderJson("{\"duplicate\":" + (count != 0) + "}");
    }

    /**
     * @Title: 删除选中角色
     * @throws SQLException
     *             void
     */
    private void deleteSelectedPermission(String[] ids) throws SQLException{
        boolean deleted = true;
        for(String id : ids){
            if(!deleteRoleAndPermission(id)){
                deleted = false;
                break;
            }
        }
        if(deleted){
            ajaxJsonSuccessMessage("删除成功！");
        }
    }

    /**
     * @Title: deleteRoleAndPermission
     * @Description:删除角色，角色-权限映射关系
     * @param id
     *            角色ID
     * @throws SQLException
     *             void
     */
    private boolean deleteRoleAndPermission(String id) throws SQLException{
        log.info("delete id:" + id);
        List<SysUserRole> userRoleList = SysUserRole.dao.find("select user_id from sys_user_role where role_id=?", id);
        SysRole role = SysRole.dao.findById(id);
        if(userRoleList != null && userRoleList.size() > 0){
            ajaxJsonErrorMessage("角色[" + role.getStr("name") + "]下存在管理员，删除失败！");
            return false;
        }
        role.set("is_deleted", 1);
        role.set("last_updated_by", getAdminId());
        role.set("last_updated_time", new Date());
        role.update();

        deleteRolePermissionMap(id);

        return true;
    }

    private int getAdminId(){
        return InterfaceUtil.getAdminId();
    }

    /**
     * @Title: deleteRolePermissionMap
     * @Description:删除角色 权限关系映射表中该角色对应的所有权限
     * @param roleId
     *            void
     */
    private void deleteRolePermissionMap(String roleId){

        String sql = " delete from sys_role_permission where role_id = " + roleId;

        Db.update(sql);
    }

    private List<RoleBean> getRoleTypes(int adminRoleId, int selectedType){
        SysRole role = SysRole.dao.findById(adminRoleId);
        int roleType = role.getInt("type");
        if(selectedType == 0){
            selectedType = roleType;
        }
        List<RoleBean> roleLevels = new ArrayList<RoleBean>(4);
        for(int i = 0; i < ROLE_TYPE_ARRAY.length; i++){
            String name = getRoleTypeName(ROLE_TYPE_ARRAY[i]);
            if(null != name){
                RoleBean roleTypeBean = new RoleBean(name, ROLE_TYPE_ARRAY[i]);
                if(selectedType == ROLE_TYPE_ARRAY[i]){
                    roleTypeBean.setSelected(true);
                }
                roleLevels.add(roleTypeBean);
            }
        }
        return roleLevels;
    }

    /**
     * @Title: 根据当前管理员所属角色的等级，获取角色等级列表
     * @Description:角色等级(省级1>地级市级2>区县级3>网点级4),获取角色等级列表时，只能获取级别小于等于当前级别的
     * @param adminRoleId
     *            当前管理员角色ID
     * @param selectedLevel
     *            默认选中等级
     * @return List<PermissionLevel>
     */
    private List<RoleBean> getRoleLevels(int adminRoleId, int selectedLevel){
        SysRole role = SysRole.dao.findById(adminRoleId);
        int adminLevel = role.getInt("level");
        if(selectedLevel == 0){
            selectedLevel = adminLevel;
        }
        List<RoleBean> roleLevels = new ArrayList<RoleBean>(4);
        for(int i = adminLevel; i <= 4; i++){
            String name = getRoleLevelName(i);
            if(null != name){
                RoleBean permissionLevel = new RoleBean(name, i);
                if(selectedLevel == i){
                    permissionLevel.setSelected(true);
                }
                roleLevels.add(permissionLevel);
            }
        }
        return roleLevels;
    }

    /**
     * @Title: 根据Level值获取角色等级名称
     */
    private String getRoleLevelName(int level){
        String levelName = null;
        switch(level){
            case 1:
                levelName = "省级";
                break;
            case 2:
                levelName = "地市级";
                break;
            case 3:
                levelName = "区县级";
                break;
            case 4:
                levelName = "网点级";
                break;
        }
        return levelName;
    }

    /**
     * @Title: 根据type值获取角色类型名称
     */
    private String getRoleTypeName(int level){
        String levelName = null;
        switch(level){
            case Constant.ROLE_TYPE_ADMIN:
                levelName = "普通管理员";
                break;
            case Constant.ROLE_TYPE_SUPPLIER_ADMIN:
                levelName = "供应商管理员";
                break;
            case Constant.ROLE_TYPE_GOV_ENTERPRISE:
                levelName = "政企管理员";
                break;
        }
        return levelName;
    }

    /**
     * @Title: 根据当前管理员所属角色的等级，获取角色列表 *
     * @Description:角色等级(省级1>地级市级2>区县级3>网点级4),获取列表时，只能获取级别小于等于当前级别的数据 void
     */
    private void findByPageByRoleLevel(ConcurrentHashMap<String, String> searchInfo){
        String select = "select *";
        String sqlExceptSelect = "from sys_role where level >= (select level from sys_role, sys_user_role where sys_user_role.role_id = sys_role.id and sys_user_role.user_id="
                + getAdminId() + ")  and is_deleted=0 ";
        sqlExceptSelect += getSqlExceptSelect(searchInfo);

        Page<SysRole> pager = SysRole.dao.paginate(getParaToInt(PAGE_NUMBER, 1), getParaToInt(PAGE_SIZE, 10), select,
                                                   sqlExceptSelect);
        setAttr(PAGER, pager);
    }

    /**
     * 获取查询语句
     */
    public String getSqlExceptSelect(ConcurrentHashMap<String, String> searchInfo){
        String sqlExceptSelect = "";
        for(Entry<String, String> item : searchInfo.entrySet()){
            sqlExceptSelect += buildQuery(item);
        }
        sqlExceptSelect += " order by id desc";

        // System.out.println("sqlExceptSelect = " + sqlExceptSelect);
        return sqlExceptSelect;
    }

    private String buildQuery(Entry<String, String> item){
        return " and " + item.getKey() + " like '%" + item.getValue() + "%'";
    }

    /**
     * @Title: 根据当前管理员所属角色的等级，获取角色列表 *
     * @Description:角色等级(省级1>地级市级2>区县级3>网点级4),获取列表时，只能获取级别小于等于当前级别的数据 void
     */
    private void findActiveRoleByPageByRoleLevel(String keyword){
        String select = "select *";
        String sqlExceptSelect = "from sys_role where level >= (select level from sys_role, sys_user_role where sys_user_role.role_id = sys_role.id and sys_user_role.user_id="
                + getAdminId() + ") and is_deleted=0 and is_active=1 ";
        if(StrKit.notBlank(keyword)){
            sqlExceptSelect += "and name like '%" + keyword + "%'";
        }
        Page<SysRole> pager = SysRole.dao.paginate(getParaToInt(PAGE_NUMBER, 1), getParaToInt(PAGE_SIZE, 10), select,
                                                   sqlExceptSelect);
        setAttr(PAGER, pager);
    }
}
